#include "http.h"

int XCOUNT = 0;

QString Http::MultipartFormData = "multipart/form-data";
QString Http::XWWWFormUrlencoded = "application/x-www-form-urlencoded";

Http::Http():QTcpSocket()
{	
	_content_type = "";
	_isPost = false;
	_follow_moving = false;
}


void Http::setHost(const QString &host,quint16 port){
	_host = host;
	_port = port;
}

/// добавляет переменную куки.
void Http::addCookie(const QString &name,const QString &value){
	_cookies[name] = value;	
}
/// добавлет переменную (get,post).
void Http::addVariable(const QString &name,const QString &value){
	_text_variables[name] = value;	
}

void Http::addVariable(const QString &name,int value)
{
	addVariable(name,QString::number(value));
}

void Http::addHeaderVariable(const QString &name,const QString &value){
	_header_variables[name] = value;
}


void Http::removeHeaderVariable(const QString &name)
{
	_header_variables.remove(name);
}

QString Http::cookies(){
	QStringList slist;
	QMapIterator<QString,QString> i(_cookies);
	while(i.hasNext()){
		i.next();
		slist.push_back(QString("%1=%2").arg(i.key()).arg(i.value()));		
	}
	return slist.join(";");
}
/// создает заголовок
QByteArray Http::makeHeader(const QString &path,QString method){
	QString header;
	QUrl url;
	url.setHost(_host);
	url.setPath(path);
	QString qget = path;
	if(!_proxy_addr.isEmpty()){
		qget = QString("http://%1%2").arg(_host).arg(path);
	}
	header = QString("%1 %2 HTTP/1.0\r\n").arg(method).arg(qget);
	addHeaderVariable("Host",_host);
	if(_content_type==MultipartFormData){
		addHeaderVariable("Content-Type",MultipartFormData+"; boundary="+boundary());
	}
	else{
		if(!_content_type.isEmpty()) addHeaderVariable("Content-Type",_content_type);
	}
	QMapIterator<QString,QString> i(_header_variables);
	while(i.hasNext()){
		i.next();
		header += QString("%1: %2\r\n").arg(i.key()).arg(i.value());		
	}
	// подставновка кукисов
	if(_cookies.size())
		header += QString("Cookie: %1\r\n").arg(cookies());		
	
	header += "\r\n";
	
	return header.toUtf8();
}
QByteArray Http::encoding(){
	return "Windows-1251";	
}
/// отправить get запрос.
/// \param QByteArray &content - буффер, куда сохранится результат
QByteArray Http::get(const QString &path){
	//qDebug() << 7 << Q_FUNC_INFO << _isPost << path;
	if(_isPost) return post(path);
	//while(XCOUNT>=5){}
	//XCOUNT++;	
	//qDebug() << "Http::get started" << XCOUNT;
	QByteArray header = makeHeader(path,"GET")+_body;
	return processAnswer(sendQuery(header));
}

/// отправить post запрос.
QByteArray Http::post(const QString &path)
{
	//qDebug() << 7 << Q_FUNC_INFO << path;
	QByteArray content = joinVariables();
	if(content.isEmpty()) content = _body;
	addHeaderVariable("Content-Length",QString::number(content.size()));	
	//qDebug() << makeHeader(path,"POST")+content;
	return processAnswer(sendQuery(makeHeader(path,"POST")+content));
}

QByteArray Http::joinVariables()
{	
	QByteArray content;
	if(_content_type!=MultipartFormData){ // обычное содержимое		
		QMapIterator<QString,QString> i(_text_variables);	
		while(i.hasNext()){
			i.next();
			//content += QString("%1=%2").arg(i.key()).arg(QString(QUrl::toPercentEncoding(i.value()))).toUtf8();		
			content += QString("%1=%2").arg(i.key()).arg(i.value()).toUtf8();		
			if(i.hasNext()) content += "&";				
		}	
	}
	else{ // мультисодержимое.
		QMapIterator<QString,QString> i(_text_variables);	
		//content = "--";
		while(i.hasNext()){
			i.next();
			content += QString("--%1\r\nContent-Disposition: form-data; name=\"%2\"\r\n\r\n%3\r\n").arg(boundary()).arg(i.key()).arg(i.value()).toUtf8();		
		}	
		
		QMapIterator<QString,QString> f(_files);	
		//content = "--";
		while(f.hasNext()){
			f.next();
			QFile file(f.value());
			if(!file.open(QIODevice::ReadOnly)) continue;
			content += QString("--%1\r\nContent-Disposition: form-data; name=\"%2\"; filename=\"%3\"\r\nContent-Type: %4\r\n\r\n").arg(boundary()).arg(f.key()).arg(fileName(f.value())).arg(fileType(f.value())).toUtf8();					
			content += file.readAll();
			content += "\r\n";
		}	
		
		content += "--"+boundary()+"--\r\n\r\n";						
	}
	
	return content;
}

QString Http::fileName(const QString &fname)
{
	return QFileInfo(fname).fileName();
}

QString Http::fileType(const QString &/*fname*/)
{
	return "image/png";
}

QByteArray Http::sendQuery(const QByteArray &header)
{
	//qDebug() << Q_FUNC_INFO;
	_lasterror = QString();
	QString x = QString::fromUtf8(header);
	
	//qDebug() << 7 << Q_FUNC_INFO<<"start"<<x.split("\r\n").at(0);
	QString host = _host;
	quint16 port = _port;
	//qDebug() << Q_FUNC_INFO << _host;
	if(!_proxy_addr.isEmpty()){
		host = _proxy_addr;
		port = _proxy_port;
	}
	//qDebug() << "connecting to host"<<host<<"port"<<port;
	//qDebug() << "x1";
	connectToHost(host,port);
	if(!waitForConnected(30000)){
		_lasterror = trUtf8("Таймаут соединения с сервером");
		//qWarning() << "not connected";
		XCOUNT--;
		return QByteArray();
	}
	qDebug() << "header="<<header;
	write(header);
	if(!waitForBytesWritten(-1)){
		qWarning() << "not writed";
		XCOUNT--;
		return QByteArray();
	}
	//qDebug() << "x3";
	QByteArray answer;	
	QByteArray data;
	while(waitForReadyRead(-1)){
		data = readAll();				
		answer += data;
	}
	//qDebug() << "x4";
	disconnectFromHost();
	//qDebug() << 7 << Q_FUNC_INFO<<"end";
	//Q_ASSERT(answer.left(4)!="HTTP");
	//qDebug() <<"answer="<< answer;
	//XCOUNT--;
	
	//qDebug() << "Http::get finished";
	//qDebug() << Q_FUNC_INFO << "header=" << header;	
	//qDebug() << Q_FUNC_INFO << "answer=" << answer;	
	return answer;
}
QByteArray Http::processAnswer(const QByteArray &answer){
	QStringList slist;
	slist = QString(answer).split("\r\n\r\n");

	if(slist.size()==0){ 
		return false;
	}
	QString header = slist[0];
	if (slist.size()<2){
		return QByteArray();
	}
	_lastQueryResultCode = QString(header).left(12).right(3).toInt();	
	if(_lastQueryResultCode==302 && _follow_moving){
		return followMoving(header);// следовать перенаправлению.
	}//qDebug() <<7<<302<< cookie("sessionid");
	QByteArray content = answer.right(answer.size()-header.size()-4);
	splitCoockie(header.split("\r\n"));
	return content;
}

QString Http::headerParam(const QString &header, const QString name)
{
	QStringList lines = header.split("\n");
	foreach(QString line,lines){
		if(line.split(":").at(0)==name){
			return line.split(":").at(1).simplified();
		}		
	}
	return QString();
}

QByteArray Http::followMoving(const QString &header)
{
	//qDebug() << Q_FUNC_INFO << header;
	removeHeaderVariable("Content-type");
	removeHeaderVariable("Content-Length");
	QString newurl = headerParam(header,"Location");
	return get(newurl);
}

void Http::splitCoockie(const QStringList &header){
	foreach(QString str,header){
		// разбор кукисов
		QRegExp rx("^Set-Cookie\\:(.*)$");
		if(rx.indexIn(str)!=-1){
			QString cstr = rx.cap(1);
			QStringList xlist = cstr.split(";");
			foreach(cstr,xlist){
				QStringList clist = cstr.split("=");
				if(clist.size()<2) continue;
				addCookie(clist[0].simplified(),clist[1].simplified());
			}
		}
	}
}
/**
* установить проксисервер для соединения.
*/
void Http::setProxy(const QString &host, quint16 port)
{
	//qDebug() << "Http::setProxy host="<<host<<"port="<<port;
	_proxy_addr = host;
	_proxy_port = port;
}

int Http::lastQueryResultCode()
{
	return _lastQueryResultCode;
}

QString Http::cookie(const QString &name)
{
	return _cookies[name];
}

void Http::setContentType(const QString &ct)
{
	_content_type = ct;
}

QString Http::boundary()
{
	return "---------------------------56413718916406600241351563310";
}

void Http::addFile(const QString &name,const QString &fname)
{
	_content_type = MultipartFormData;
	setMethod("POST");
	_files[name]=fname;
}

void Http::setMethod(const QString &mt)
{
	if(mt.toUpper()=="POST") _isPost = true;
}

void Http::setFollowMoving(bool f)
{
	_follow_moving = f;
}

void Http::setUser(const QString &user,const QString &passwd)
{
	QString auth_data = QString("%1:%2").arg(user).arg(passwd).toUtf8().toBase64();
	addHeaderVariable("Authorization","Basic "+auth_data);
}

QString Http::lastError()
{
	return _lasterror;
}

void Http::setBody(const QByteArray &data)
{
	_body = data+"\r\n\r\n";
}
